#ifndef SCOPED_REF_H
#define SCOPED_REF_H

#include "base/macro_def.h"
#include "base/atomic_x86_64.h"

class RefCount {
  public:
    RefCount() {
      atomic64_set(&count_, 1);
    }

    int32_t Count() {
      return atomic_read(&count_);
    }

    void Ref() {
      atomic_inc(&count_);
    }

    void UnRef() {
      if (atomic_dec_and_test(&count_)) {
        delete this;
      }
    }

  private:
    atomic_t count_;

    // only delete by unref().
    virtual ~RefCount() {
    }

    DISALLOW_COPY_AND_ASSIGN(RefCount);
};

template<typename Type>
class scoped_ref {
  public:
    explicit scoped_ref(Type* t = NULL)
        : rc_(t) {
      enum {
        T = sizeof(Type),
      };
    }

    void reset(Type* t) {
      enum {
        T = sizeof(Type),
      };
      if (rc_ != NULL) {
        rc_->UnRef();
      }

      rc_ = t;
    }

    void operator =(Type* rhs) {
      CHECK_NOTNULL(rhs);
      if (rc_ != NULL) {
        rc_->UnRef();
        rc_ = NULL;
      }

      rc_ = rhs;
      if (rhs != NULL) {
        rhs->Ref();
      }
    }

    ~scoped_ref() {
      if (rc_ != NULL) {
        rc_->UnRef();
      }
    }

    Type* operator->() {
      CHECK(rc_ != NULL);
      return rc_;
    }

    Type* get() const {
      return rc_;
    }
    Type* release() {
      Type* tmp = rc_;
      rc_ = NULL;
      return tmp;
    }

  private:
    Type* rc_;

    DISALLOW_COPY_AND_ASSIGN(scoped_ref);
};

#endif  // SCOPED_REF_H
